from Activity import Activity;
# from HmmSubject import HmmSubject;
# from HmmGroup import HmmGroup;
# from VarElimination import VarElimination;
from InferenceBB import InferenceBB;
from KnowledgeSource import KnowledgeSource;
import random;

class BlackBoard(object):
    def __init__(self, inputSim):
        self.pgm = inputSim.pgm;
        self.graph = self.pgm.Graph();
        self.inputSim = inputSim;
        self.aActs_Time = dict();
        self.aKeys_Time = dict();
        self.aOngoingActs = dict();
        self.aNewActsT = dict();
        self.aNullNodes = dict();
        self.aMExNodes = dict();
        self.knowledgeSrc = KnowledgeSource();
        self.inferenceBB = InferenceBB(self);
        
    def getSubjGrp(self, sTargetSubj, sTime):
        #Add All Linked Act's Subjects to a Group
        aSubjGrp, aActGrp = [], [];
        aMoreSubjects = [sTargetSubj];
        while len(aMoreSubjects)>0:
            aSubjGrp.append(aMoreSubjects[0]);            
            if self.aActs_Time.has_key((aMoreSubjects[0],sTime)):
                for actM in self.aActs_Time[(aMoreSubjects[0],sTime)]:
                    if not(actM in aActGrp):
                        aActGrp.append(actM);
                    for subject in actM.rootAct.aOnlySubjects:
                        if not(subject in aMoreSubjects) and not(subject in aSubjGrp):
                            aMoreSubjects.append(subject);
                del aMoreSubjects[0];
        return [aSubjGrp, aActGrp];
    
    def addGrp(self, aRemSubjGrp, aRemActGrp, aAllRemSubjs, subject, sT):
        [remSubjGrp, remActGrp] = self.getSubjGrp(subject, sT);
        if aRemSubjGrp.has_key(sT) and aRemActGrp.has_key(sT):
            for subjGrp in remSubjGrp:
                if not(subjGrp in aRemSubjGrp[sT]):
                    aRemSubjGrp[sT].append(subjGrp);
            for actGrp in remActGrp:
                if not(actGrp in aRemActGrp[sT]):
                    aRemActGrp[sT].append(actGrp);
        else:
            aRemSubjGrp[sT] = remSubjGrp;
            aRemActGrp[sT] = remActGrp;
        for subject in remSubjGrp:
            if not(subject in aAllRemSubjs):
                aAllRemSubjs.append(subject);
        return [aRemSubjGrp, aRemActGrp, aAllRemSubjs];
    
    def removeAct(self, sActCode):
        #Find Activity Node (by its given Code)
        aRemActs = [];
        aSubjects = self.aKeys_Time.keys();
        aRemSubjects, aRemTimes = [], [];
        aRemSubjGrp, aRemActGrp = dict(), dict();
        aAllRemSubjs = [];
        print "\n\n---Activity To Remove:---";
        for subject in aSubjects:
            for sT in self.aKeys_Time[subject]:
                for actM in self.aActs_Time[(subject,sT)]:
                    if actM.sId.split(".")[0]==sActCode and not(actM in aRemActs):
                        aRemActs.append(actM);
                        #Collect its Subjects & Time-Steps
                        for remSubject in actM.rootAct.aOnlySubjects:
                            if not(remSubject in aRemSubjects):
                                aRemSubjects.append(remSubject);
                        for remTime in actM.rootAct.aTimes:
                            nRemTime = int(remTime);
                            if not(nRemTime in aRemTimes):
                                aRemTimes.append(nRemTime);
                        [aRemSubjGrp, aRemActGrp, aAllRemSubjs] = self.addGrp(aRemSubjGrp, aRemActGrp, aAllRemSubjs, subject, sT);
                        if len(aRemActs)==1: #Get all segments at TailT (due to this remAct doesn't have a Sgmt at T0)
                            sT0 = aRemActs[0].rootAct.aTimes[0];
                            for subjectT0 in aRemActs[0].rootAct.aOnlySubjects:
                                if self.aActs_Time.has_key((subjectT0,sT0)):
                                    for actM0 in self.aActs_Time[(subjectT0,sT0)]:
                                        if actM0.bCopySegment:
                                            aRemActs.append(actM0);
                                            [aRemSubjGrp, aRemActGrp, aAllRemSubjs] = self.addGrp(aRemSubjGrp, aRemActGrp, aAllRemSubjs, subjectT0, sT0);
                        print actM.rootAct.name;
        #Collect all time steps of each subject's timelines
        nT0, nT1 = aRemTimes[0], aRemTimes[-1];
        for subject in aAllRemSubjs:
            for sT in self.aKeys_Time[subject]:
                nT = int(sT);
                if nT>nT0 and nT<nT1 and not(nT in aRemTimes):
                    aRemTimes.append(int(sT));
        aRemTimes.sort();
        #Prepare to Change Ranges of Remaining Segments (Get nodes AfterT1 & BeforeT0)
        if aRemActs==[]: return;
        sT0, sT1 = str(aRemTimes[0]), str(aRemTimes[-1]);
        aAfterT1, aBeforeT0 = dict(), dict();
        for subject in aAllRemSubjs:
            aSubjTs = self.aKeys_Time[subject];
            #Get T1+1 for each Subject's Timeline
            if not(sT1 in aSubjTs):
                aSubjTs_Reversed = list(aSubjTs);                
                aSubjTs_Reversed.reverse();
                for sT in aSubjTs_Reversed:
                    if int(sT) < int(sT1) and aSubjTs.index(sT)+1 < len(aSubjTs):
                        aAfterT1[subject] = aSubjTs[aSubjTs.index(sT)+1];
                        break;
                    elif int(sT) < int(sT1) and aSubjTs.index(sT)+1 >= len(aSubjTs):
                        break;
            elif aSubjTs.index(sT1)+1 < len(aSubjTs):
                aAfterT1[subject] = aSubjTs[aSubjTs.index(sT1)+1];
            #Get T0-1 for each Subject's Timeline
            if not(sT0 in aSubjTs):
                for sT in aSubjTs:
                    if int(sT) > int(sT0) and aSubjTs.index(sT)-1 >= 0:
                        aBeforeT0[subject] = aSubjTs[aSubjTs.index(sT)-1];
                        break;
                    elif int(sT) > int(sT0) and aSubjTs.index(sT)-1 < 0:
                        break;
            elif aSubjTs.index(sT0)-1 >= 0:
                aBeforeT0[subject] = aSubjTs[aSubjTs.index(sT0)-1];
        #Get All Head Nodes between T0 & T1 (only those whose Subjects became part of the Group)
        aHeadActs_T0_to_T1 = [];
        for nT in aRemTimes:
            sT = str(nT);
            for subject in aAllRemSubjs:
                if self.aActs_Time.has_key((subject, sT)):
                    for actM in self.aActs_Time[(subject, sT)]:
                        if not(actM.bCopySegment) and not(actM in aHeadActs_T0_to_T1):
                            aHeadActs_T0_to_T1.append(actM);
        #Change Ranges of T1+1
        print "\nChanging Ranges:";
        aChangedActs = [];
        for subject in aAfterT1:
            sAfterT1 = aAfterT1[subject];
            for actM in self.aActs_Time[(subject,sAfterT1)]: #For each Node at T1+1, change their T0 range             
                if actM.rootAct.actName == "Null" or actM in aChangedActs: continue;
                if actM.rootAct.nRealInitT < int(sT0): #Set Act's T0 to the T0-1 obtained above                    
                    s_T0 = aBeforeT0[subject] if aBeforeT0.has_key(subject) else str(actM.rootAct.nRealInitT);
                elif actM.rootAct.nRealInitT >= int(sT0): #Else, Set Act's T0 to InitT (its real TailT)
                    s_T0 = str(actM.rootAct.nRealInitT);
                s_T1 = actM.rootAct.aTimes[-1];
                print "---Changing Node range", actM.rootAct.name, " to: ["+s_T0+"-"+s_T1+"]";
                actM.changeInitT(s_T0);
                aChangedActs.append(actM);
        #Change Ranges of Head Nodes between T0 & T1
        for actM in aHeadActs_T0_to_T1: #For each Head Node between T0 & T1, change their T0 range
            for subject in actM.rootAct.aOnlySubjects:
                if actM.rootAct.actName == "Null" or actM in aChangedActs: continue;
                if actM.rootAct.nRealInitT < int(sT0): #Set Act's T0 to the T0-1 obtained above                    
                    s_T0 = aBeforeT0[subject] if aBeforeT0.has_key(subject) else str(actM.rootAct.nRealInitT);
                elif actM.rootAct.nRealInitT >= int(sT0): #Else, Set Act's T0 to InitT (its real TailT)
                    s_T0 = str(actM.rootAct.nRealInitT);
                s_T1 = actM.rootAct.aTimes[-1];
                print "---Changing Node range", actM.rootAct.name, " to: ["+s_T0+"-"+s_T1+"]";
                actM.changeInitT(s_T0);
                aChangedActs.append(actM);
        #Add Rest of Segment Nodes to Remove
        for nT in aRemTimes:
            sT = str(nT);
            for subject in aAllRemSubjs:
                if self.aActs_Time.has_key((subject,sT)):
                    for actM in self.aActs_Time[(subject,sT)]:
                        if actM.bCopySegment and not(actM in aRemActs):
                            aRemActs.append(actM);
        #Add Time-Points for Collisions & Relinking
        aTimes_Coll_Relinks, aNodes_Coll_Relinks = [], [];
        for actM in aChangedActs:
            sT = actM.rootAct.aTimes[-1];
            if sT!=sT1 and sT!=sT0 and not(sT in aTimes_Coll_Relinks):
                aTimes_Coll_Relinks.append(sT);
            if sT!=sT1 and sT!=sT0 and not(actM in aTimes_Coll_Relinks):
                aNodes_Coll_Relinks.append(actM);
        #Removing All Act nodes of this Activity Code (and all others affected by this)
        aT, aT_Relink, aRemSubjects, aRemSubj_Relink = [], [], [], [];
        print "\nOld self.aActs_Time:", self.aActs_Time;
        print "Old self.aKeys_Time:", self.aKeys_Time;        
        if self.aOngoingActs.has_key(sActCode): #Removing Act if it's Ongoing
            print "*****", self.aOngoingActs;
            del self.aOngoingActs[sActCode];
            print "*****", self.aOngoingActs;
        for remAct in aRemActs: #Removing All Acts from TimeLine
            if remAct.rootAct.actName=="Null": continue;
            sT = remAct.rootAct.aTimes[-1];
            if not(sT in aT):
                aT.append(sT);                            
            for subject in remAct.rootAct.aOnlySubjects:
                if not(subject in aRemSubjects):
                    aRemSubjects.append(subject);
                iRemAct = self.aActs_Time[(subject,sT)].index(remAct);
                del self.aActs_Time[(subject,sT)][iRemAct];
            print "Removing Act:", remAct.rootAct.name;
            remAct.removeAct(self.graph);
        print aT;
        #Remove Null Nodes
        for sT in aT:
            self.removeNullNodes(aRemSubjects, sT);
        for sT in aT: #Removing Time-Slots from TimeLine (if NO Act Sgms exist there)
            print "New self.aActs_Time:", self.aActs_Time;
            print "New self.aKeys_Time:", self.aKeys_Time;
            for subject in aRemSubjects:
                if self.aActs_Time.has_key((subject,sT)):
                    if len(self.aActs_Time[(subject,sT)])==0:
                        print "Removing (Subject,Time):", (subject,sT);
                        del self.aActs_Time[(subject,sT)];
                        del self.aKeys_Time[subject][self.aKeys_Time[subject].index(sT)];
                        if len(self.aKeys_Time[subject])==0:                            
                            del self.aKeys_Time[subject];
                    else:
                        if not(int(sT) in aT_Relink):
                            aT_Relink.append(int(sT));
                        if not(subject in aRemSubj_Relink):
                            aRemSubj_Relink.append(subject);
        print "New self.aActs_Time:", self.aActs_Time;
        print "New self.aKeys_Time:", self.aKeys_Time;
        #Get Collisions of Remaining Nodes at T1+1 (and Head Nodes between T0 & T1)
        self.aNewActsT = dict();
        for actM in aNodes_Coll_Relinks:
            self.addActCollisions(actM);
        #Add the New Sgmt Acts to the Graph & Relink everything
        print "aNewActsT_Old:", self.aNewActsT;
        self.getNextActsT();
        print "aNewActsT_New:", self.aNewActsT;
        aAddedActs = [];
        for subject in self.aNewActsT.keys():
            for nT in self.aNewActsT[subject]:
                aAddedActs = self.addNodesToGraph(subject, str(nT), aAddedActs);   
        print "\nRelinking on Times:", aTimes_Coll_Relinks;
        for actM in aAddedActs:
            print "Added Sgmt:", actM.rootAct.name;
            if not(actM in aNodes_Coll_Relinks):
                aNodes_Coll_Relinks.append(actM);
        for sT in aTimes_Coll_Relinks:
            for subject in aAllRemSubjs:
                if self.aActs_Time.has_key((subject,sT)):
                    for actM in self.aActs_Time[(subject,sT)]:
                        if not(actM in aNodes_Coll_Relinks) and actM.rootAct.actName!="MEx":
                            aNodes_Coll_Relinks.append(actM);
        self.linkActivities(aNodes_Coll_Relinks);
        #Remove Mutual Exclusive Nodes
        for nT in aRemTimes:
            for subject in aAllRemSubjs:
                self.removeMExNodes(subject, str(nT));
        print "\nGraph:";
        self.printGraph();
        self.graph.setup();
            
    def check_InitEnd_Act(self, sActCode, sT0, sT1):
        #Check if there is NOT other Head nodes (in this InitT/EndT)
        aSubjects = self.aKeys_Time.keys();
        for subject in aSubjects:
            if self.aActs_Time.has_key((subject,sT0)):
                for actM in self.aActs_Time[(subject,sT0)]:
                    if actM.rootAct.actName=="Null": continue;
                    sId = actM.rootAct.sId.split(".")[0];
                    if sId!=sActCode and not(actM.bCopySegment):
                        return []; #If another Head is found, then don't remove anything
        #Check if there is NOT other Tail nodes (in this InitT/EndT)
        if sT1=="":
            return [];
        for subject in aSubjects:
            if self.aActs_Time.has_key((subject,sT1)):
                for actM in self.aActs_Time[(subject,sT1)]:
                    if actM.rootAct.actName=="Null" or sT0!=actM.rootAct.aTimes[0]: continue;
                    sId = actM.rootAct.sId.split(".")[0];
                    if sId!=sActCode and not(self.graph.idndict.has_key(sId+"."+sT0)):
                        return []; #If another Tail is found, then don't remove anything
        #If neither Tails nor Heads were found (in this InitT/EndT), then remove all these Acts
        aRemActs = [];
        for subject in aSubjects:
            if self.aActs_Time.has_key((subject,sT0)):
                for actM in self.aActs_Time[(subject,sT0)]:
                    if actM.rootAct.sId!=(sActCode+"."+sT0) and not(actM in aRemActs):
                        aRemActs.append(actM);
        return aRemActs;
    
    def removeNullNodes(self, aRemSubjects, sTime):
        print "Checking Null Time:", sTime;
        bNullFound = False;
        for subject in aRemSubjects:
            if self.aActs_Time.has_key((subject,sTime)):
                bNullFound = True;
                break;
        if not(bNullFound): return;
        aRemNulls = [];
        aArgs = [];
        for subject in aRemSubjects:
            if self.aActs_Time.has_key((subject,sTime)):
                for node in self.aActs_Time[(subject,sTime)]: #Get All Arg Subjects of this "t"
                    if node.rootAct.actName=="Null": continue;
                    for sArg in node.rootAct.aSubjects:
                        if sArg=="*": continue;
                        if not(sArg in aArgs):
                            aArgs.append(sArg);
        for subject in aRemSubjects:
            if self.aActs_Time.has_key((subject,sTime)):
                for node in self.aActs_Time[(subject,sTime)]: #For each Null Node in this "t"            
                    if node.rootAct.actName!="Null": continue;
                    if not(node.rootAct.aSubjects[0] in aArgs) and not(node in aRemNulls):
                        aRemNulls.append(node);
        for subject in aRemSubjects:
            if self.aActs_Time.has_key((subject,sTime)):
                for remAct in aRemNulls: #Removing All Acts from TimeLine
                    if remAct in self.aActs_Time[(subject,sTime)]:
                        iRemAct = self.aActs_Time[(subject,sTime)].index(remAct);
                        del self.aActs_Time[(subject,sTime)][iRemAct];
                        print "Removing NullAct:", remAct.rootAct.name;
                        remAct.removeAct(self.graph);
    
    def makeUsrSegment(self, nTime):
        if self.aActs_Time.has_key(str(nTime)): return;
        aTimes = [];
        for sT in self.aKeys_Time:
            aTimes.append(int(sT));
        aTimes.sort();
        sT0, sT1 = "None", "None";
        for actTime in aTimes:
            if actTime>nTime:
                sT0 = str(self.getPastKey(str(actTime)));
                sT1 = str(actTime);
                break;
        if sT0=="None" and sT1=="None": #If at that "t" all is Ongoing
            for sCode in self.aOngoingActs:
                ongoingAct = self.aOngoingActs[sCode][0];
                sInitT = sT0;
                if sInitT=="None": sInitT = "0";
                segmentAct = self.getSegmentAct(ongoingAct, sInitT, nTime); #Add copy of this node
                self.addActToBB(segmentAct);                
        else: #If it's not Ongoing
            for nodeM in self.aActs_Time[sT1]:
                if nodeM.rootAct.actName=="Null": continue;
                sInitT = sT0;
                if sInitT=="None": sInitT = "0";
                segmentAct = self.getSegmentAct(nodeM, sInitT, nTime); #Add copy of this node
                self.addActToBB(segmentAct);
        self.addNodesToGraph(str(nTime));
        if sT0!="None":
            self.linkActivities(sT0);
        self.linkActivities(str(nTime));
        if sT1!="None":
            self.linkActivities(sT1);
        self.addMExNodes(str(nTime));
        self.graph.setup();
        
    def removeUsrSegment(self, nTime):
        aTimes = [];
        for sT in self.aKeys_Time:
            aTimes.append(int(sT));
        aTimes.sort();
        sT0, sT1 = "None", "None";
        for actTime in aTimes:
            if actTime>nTime:
                sT0 = str(nTime); #str(self.getPastKey(str(actTime)));
                sT1 = str(actTime);
                break;        
        if sT0=="None": sT0 = str(nTime);
        for remAct in self.aActs_Time[sT0]: #Removing All Acts from TimeLine
            if remAct.rootAct.actName=="Null": continue;
            iRemAct = self.aActs_Time[sT0].index(remAct);
            del self.aActs_Time[sT0][iRemAct];
            print "Removing Act:", remAct.rootAct.name;
            remAct.removeAct(self.graph);
        #Remove Null Nodes
        self.removeNullNodes(sT0);
        #Removing Time-Slots from TimeLine (if NO Act Sgms exist there)
        if len(self.aActs_Time[sT0])==0:
            print "Removing Time:", sT0;
            del self.aActs_Time[sT0];
            del self.aKeys_Time[self.aKeys_Time.index(sT0)];
        #Relink All remaining Act nodes
        if sT1!="None":
            self.linkActivities(sT1);
        #Remove Mutual Exclusive Nodes
        self.removeMExNodes(sT0);
        self.graph.setup();
    
    def getSegmentAct(self, actModel, nInitT, nEndT):
        nInitT = int(nInitT); nEndT = int(nEndT);
        #Activity:
        newAct = self.createActNode(None, actModel.rootAct, nInitT, nEndT, bRoot=True);
        #Create SubActivities:
        for childNode in actModel.aChildNodes:
            #SubActivity:
            newAct = self.createActNode(newAct, childNode, nInitT, nEndT, bRoot=False);
#         print "---Created Segment Activity Node:";
#         self.inputSim.printActNode(newAct);
        return newAct;
    
    #Create a new Segment copy from this existing actNode Activity from times nInitT to nEndT 
    def createActNode(self, actModel, actNode, nInitT, nEndT, bRoot=False):
        sActName = actNode.actName;
        sId = actNode.sId.split(".")[0] + "." + str(nEndT);
        aSubjects = []; #Only Actors observed in this Time Event
        aActorsAll = list(actNode.aActorsAll); #All Actors seen so far in this Event
        aActorTypes = list(actNode.aActorTypes); #All Actor Types
        aActorTimes = []; #All Actor Times
        aActorRoles = list(actNode.aActorRoles); #All Actor Roles
        aActorsInfo = []; #All Actor Info (ActorsAll, Types, Times, Roles)
        if bRoot: #If we are creating the root of this new Segment, then check its corresponding Args (for this time interval)
            for i,actorT in enumerate(actNode.aActorTimes):
                aActorTimes.append(list(actorT));
                nActorInit = int(actorT[0].replace("+",""));
                nActorEnd = int(actorT[1].replace("+",""));
                if nEndT>=nActorInit and nEndT<=nActorEnd:
                    aSubjects.append(aActorsAll[i]); #Add this Actor if it falls in actNode.aTimes
        else:
            #If this is Sub-Activity, just copy all its Subjects and ObjectTimes 
            aSubjects = list(actNode.aSubjects);
            for i,actorT in enumerate(actNode.aActorTimes):
                aActorTimes.append(list(actorT));
        nRealInitT = actNode.nRealInitT;
        aTimes = list(actNode.aTimes);
        aTimes[0] = str(nInitT);
        aTimes[-1] = str(nEndT);
        sParentsId = [];
        if bRoot==False:
            for parentId in actNode.sParentsId:
                pId = parentId.split(".")[0] + "." + str(nEndT);
                sParentsId.append(pId);
#         aScores = self.getScore(actNode.sId.split(".")[0], nEndT);
        aScores = list(actNode.aScores);
        sLocation = actNode.location;
        aActorsInfo.append(aActorsAll);
        aActorsInfo.append(aActorTypes);
        aActorsInfo.append(aActorTimes);
        aActorsInfo.append(aActorRoles);
        #Add the Activity or Sub-Activity
        if bRoot:
            actModel = Activity(self.pgm, sActName, aSubjects, nEndT, sId, True);
        actModel.makeXmlNode(sId, sActName, aSubjects, aActorsInfo, aTimes, 
                             nRealInitT, sParentsId, aScores, sLocation, bRoot);
        return actModel;
    
    def getScore(self, sCode, nEndT):
        pass;
    
    def checkSameSubjects(self, actM1, actM2):
        return True;
#         bSameSubjects = False;
#         for subject in actM1.rootAct.aSubjects:
#             if subject!="*" and subject in actM2.rootAct.aSubjects:
# #                 if self.knowledgeSrc.getGroupValidation(actM2.rootAct, "BlackBoard.checkSameSubjects")==False: continue;
#                 bSameSubjects = True;
#                 break;
#         return bSameSubjects;
        
    
    def addActCollisions(self, actModel, bAddTailSgms=True, bAddHeadSgms=True):
        aSegments = [actModel];
        aTimePts = []; #TimePoints to add Segments
        for subject in actModel.rootAct.aOnlySubjects:
            iAct = self.aKeys_Time[subject].index(str(actModel.nTime)); #Index of Activity in TimeLine
            iAct = iAct+1 if iAct<len(self.aKeys_Time[subject])-1 else iAct; #Index+1 of Activity in TimeLine (if this is NOT the last activity)
            nInitT = int(actModel.rootAct.aTimes[0]); #Init Time of this Activity
            nEndT = int(actModel.rootAct.aTimes[-1]);
            #Add TimePoints for this Action Segment
            for i in range(iAct+1): #Move from iAct+1 (Act_EndTime + 1) Backwards (up to nInitT) 
                #Note: It Consider tails/heads from any other activities after & during this activity's time range.
                #Note: It also Checks the Init of OtherActs in same Time-Step as this Act
                nEndAct = int(self.aKeys_Time[subject][iAct-i]); #End Time in Each Segment Activity
                if (nEndAct <= nInitT): #If they are NOT overlapping on each other, then NO collision exists (if the segment is before nInitT, then we have finished)
                    break;
                for actM in self.aActs_Time[(subject,str(nEndAct))]:
                    if actM.rootAct.actName=="Null": continue; #Ignore Collisions FROM: Null
                    if not(self.checkSameSubjects(actM, actModel)): continue; #If It's independent from this activity, then avoid its collisions
                    if (nEndAct > nInitT) and (nEndAct < nEndT) and not(nEndAct in aTimePts): 
                        aTimePts.append(nEndAct); #Add Segment's (End) Time Point
                    nInitActT = int(actM.rootAct.aTimes[0]);
                    if (nInitActT > nInitT) and (nInitActT < nEndT) and not(nInitActT in aTimePts):
                        aTimePts.append(nInitActT); #Add Segment's (Init) Time Point
        #Add Collision Segments (from TimePoints Obtained)
#         print "-----Adding Segments:---------";
        aTimePts.sort();
#         print "aTimePts:", aTimePts;
        if len(aTimePts)>0: #From InitAct to Pt[0]
            nEndPt = aTimePts[0];
#             print [nInitT, nEndPt];
            segmentAct = self.getSegmentAct(actModel, nInitT, nEndPt); #Add copy of this node
            self.addActToBB(segmentAct);
            aSegments.extend([segmentAct]);
        for i in range(len(aTimePts)-1): #From Pt[i] to Pt[i+1] (i>=1)
            nInitPt = aTimePts[i];
            nEndPt = aTimePts[i+1];
#             print [nInitPt, nEndPt];
            segmentAct = self.getSegmentAct(actModel, nInitPt, nEndPt); #Add copy of this node
            self.addActToBB(segmentAct);
            aSegments.extend([segmentAct]);
        
        while len(aSegments)>0:
            aSgms = self.addFurtherActCollisions(aSegments[0], bAddTailSgms, bAddHeadSgms)            
            aSegments.extend(aSgms);
            del aSegments[0];            
            if len(aTimePts)>0:
                actModel.changeInitT(aTimePts[-1]);
                aTimePts = [];
    
    def addFurtherActCollisions(self, actModel, bAddTailSgms=True, bAddHeadSgms=True):
        #Check Further Collisions on Other Activity Nodes (caused by this Activity)
        #---Collect all those Activity Nodes (Collided Activites)---
        aOtherActs_EndP, aOtherActs_InitP = [], [];
        aSgm_EndP, aSgm_InitP, aSgms = [], [], [];
        aNames_EndP, aNames_InitP = [], [];
        for subject in actModel.rootAct.aOnlySubjects:
            iAct = self.aKeys_Time[subject].index(str(actModel.nTime)); #Index of Activity in TimeLine
            nInitT = int(actModel.rootAct.aTimes[0]); #Init Time of this Activity
            #Looking for Collisions on Tail Node Activity
            for i in range(len(self.aKeys_Time[subject][:iAct])+1): #Move from HeadAct (iAct) Backwards (up to TailAct+1)
                if (int(self.aKeys_Time[subject][iAct-i]) <= nInitT): break; #If reached TailAct, then Break
                for actM in self.aActs_Time[(subject, self.aKeys_Time[subject][iAct-i])]:
                    if actM.rootAct.actName=="Null": continue; #Ignore Collisions TO: Null
                    if not(self.checkSameSubjects(actM, actModel)): continue; #If It's independent from this activity, then avoid its collisions
                    nOtherActT0 = int(actM.rootAct.aTimes[0]); 
                    if (nOtherActT0 < nInitT) and not(actM in aOtherActs_InitP): #Store collisions on Tail Act
                        aOtherActs_InitP.append(actM);
                        aSgm_InitP.append(str(nOtherActT0)+"-"+str(nInitT));
                        aNames_InitP.append(actM.rootAct.name);
            #Looking for Collisions on Head Node Activity & (Rest of) Collisions on Tail Node Activity
            #(Check all Segments from iAct+1 [every further segment must End in iAct+1])
            if iAct+1 < len(self.aKeys_Time[subject]): #If iAct+1 exists
                for actM in self.aActs_Time[(subject, self.aKeys_Time[subject][iAct+1])]: #For each Act in iAct+1
                    if actM.rootAct.actName=="Null": continue; #Ignore Collisions to Null
                    if not(self.checkSameSubjects(actM, actModel)): continue; #If It's independent from this activity, then avoid its collisions
                    nOtherActT0 = int(actM.rootAct.aTimes[0]);
                    if (nOtherActT0 < actModel.nTime) and not(actM in aOtherActs_EndP): #Store collisions on Head Act
                        aOtherActs_EndP.append(actM);
                        aSgm_EndP.append(str(nOtherActT0)+"-"+str(actModel.nTime));
                        aNames_EndP.append(actM.rootAct.name);
                    if (nOtherActT0 < nInitT) and not(actM in aOtherActs_InitP): #Store collisions on Tail Act
                        aOtherActs_InitP.append(actM);
                        aSgm_InitP.append(str(nOtherActT0)+"-"+str(nInitT));
                        aNames_InitP.append(actM.rootAct.name);
        #Add Further Collision Segments (from Collided Activities obtained)
        if bAddTailSgms:
            for otherAct_InitP in aOtherActs_InitP:
                nOtherActT0 = int(otherAct_InitP.rootAct.aTimes[0]);
                segmentAct = self.getSegmentAct(otherAct_InitP, nOtherActT0, nInitT); #Add copy of this node
                self.addActToBB(segmentAct); #Add it to the TimeLine
                otherAct_InitP.changeInitT(nInitT); #Update InitT of Segments (that collided with TailAct)
                aSgms.append(segmentAct);
        if bAddHeadSgms:
            for otherAct_EndP in aOtherActs_EndP:
                nOtherActT0 = int(otherAct_EndP.rootAct.aTimes[0]);
                if (nOtherActT0 < nInitT and bAddTailSgms): nOtherActT0 = nInitT; #Fix Init Time of NEW segment to TailAct (if was before that & TailAct was added)
                segmentAct = self.getSegmentAct(otherAct_EndP, nOtherActT0, actModel.nTime); #Add copy of this node
                self.addActToBB(segmentAct); #Add it to the TimeLine
                otherAct_EndP.changeInitT(actModel.nTime); #Update InitT of Segments (that collided with HeadAct)
                aSgms.append(segmentAct);
        return aSgms;
        
        #Print Results
#        print "---Further Collisions from:", actModel.rootAct.name;
#        print "END-Pt Collisions";
#        print "aOtherActs_EndP (Colliding With These Activities):", aNames_EndP;
#        print "aSgm_EndP (FULL Segment TimePt):", aSgm_EndP;
#        print "bAddTailSgms (Tail Collisions Added?):", bAddTailSgms;
#        print "---"
#        print "INIT-Pt Collisions";
#        print "aOtherActs_InitP (Colliding With These Activities):", aNames_InitP;
#        print "aSgm_InitP (FULL Segment TimePt):", aSgm_InitP;
#        print "bAddHeadSgms (Tail Collisions Added?):", bAddHeadSgms;
#        print "";

    def createNullNode(self, sInitT, sEndT, sSubj, nProb_ObsNull):
        sActName = "Null";
        aSubjects = [sSubj];
#         aSubjectTypes = ["-"];
#         print "NULL at:", sInitT, sEndT;
        sId = "Null_"+sSubj+"." + sEndT;
        aTimes = [sInitT, sEndT];
        aScores = [nProb_ObsNull];
        aActorsInfo = [aSubjects];
        nullActModel = Activity(self.pgm, sActName, aSubjects, 1, sId, True);
        nullActModel.makeXmlNode(sId, sActName, aSubjects, aActorsInfo, aTimes, 
                             int(sInitT), [], aScores, "", True);
        return nullActModel;
            
    
    def addActToBB(self, actModel):
        sT = str(actModel.nTime);
        for subject in actModel.rootAct.aOnlySubjects:
            if not(self.aNewActsT.has_key(subject)) or not(int(sT) in self.aNewActsT[subject]): #Bookmark the "t" points with only Newly Modified/Added Activities for each TimeLine
                if self.aNewActsT.has_key(subject):
                    self.aNewActsT[subject].append(int(sT));
                else:
                    self.aNewActsT[subject] = [int(sT)];
        #Add a Null Node
        for sSubj in actModel.rootAct.aSubjects:
            if sSubj=="*": continue;
            bNullFound = False;
            if self.aActs_Time.has_key((sSubj,sT)):
                for actM in self.aActs_Time[(sSubj,sT)]:
                    if actM.rootAct.sId=="Null_"+sSubj+"."+sT:
                        bNullFound = True;
            if not(bNullFound):
                nullNode = self.createNullNode("0", sT, sSubj, actModel.nProb_ObsNull);
                if self.aActs_Time.has_key((sSubj,sT)): #If Existing Time Point
                    self.aActs_Time[(sSubj,sT)].append(nullNode);
                else: #If NEW Time Point
                    self.aActs_Time[(sSubj,sT)] = [nullNode];
                    self.addKeyTime(sSubj, sT);
        #Add the given ActModel
        for subject in actModel.rootAct.aOnlySubjects:
            if self.aActs_Time.has_key((subject,sT)): #If Existing Time Point
                self.aActs_Time[(subject,sT)].append(actModel);
            else: #If NEW Time Point
                self.aActs_Time[(subject,sT)] = [actModel];
                self.addKeyTime(subject, sT);

    def checkOngoingAct(self, actModel):
        bIsOngoing = actModel.rootAct.aTimes[-1].endswith("+");
        bWasAdded = self.aOngoingActs.has_key(actModel.sId.split(".")[0]);
#         print "[bIsOngoing, bWasAdded]:", [bIsOngoing, bWasAdded];
        if bIsOngoing and bWasAdded:
            self.updateOngoingAct(actModel);
        elif bIsOngoing and not(bWasAdded):
            self.addOngoingAct(actModel);
        elif not(bIsOngoing) and bWasAdded:
            self.updateOngoingAct(actModel);
            del self.aOngoingActs[actModel.sId.split(".")[0]];
        else:
            return False;
        return True;

    def updateOngoingAct(self, ongoingAct):
        #Update this ongoingAct (by adding another copy in latest Time-Step)
        iKey = ongoingAct.sId.split(".")[0];
        self.aOngoingActs[iKey][0] = ongoingAct;
        nInitT = self.aOngoingActs[iKey][2]; #Latest Time Added before
        nEndT = int(ongoingAct.rootAct.aTimes[-1].replace("+",""));
        ongoingAct.rootAct.aTimes[0] = str(nInitT);
        ongoingAct.rootAct.aTimes[-1] = str(nEndT);
        self.aOngoingActs[iKey][2] = nEndT;
            
    def addOngoingAct(self, ongoingAct):
        bAbleToAdd = True;
        nEndT = int(ongoingAct.rootAct.aTimes[-1].replace("+",""));
        nInitT = int(ongoingAct.rootAct.aTimes[0]);
        ongoingAct.rootAct.aTimes[0] = str(nInitT);
        ongoingAct.rootAct.aTimes[-1] = str(nEndT);
        self.aOngoingActs[ongoingAct.sId.split(".")[0]] = [ongoingAct, bAbleToAdd, nEndT];
#         print "self.aOngoingActs", self.aOngoingActs;
    
    def getNextActsT(self):
        for subject in self.aNewActsT.keys():
            for i in range(len(self.aKeys_Time[subject])-1):
                nKeyT0 = int(self.aKeys_Time[subject][i]);
                nKeyT1 = int(self.aKeys_Time[subject][i+1]);
                if nKeyT0 in self.aNewActsT[subject] and not(nKeyT1 in self.aNewActsT[subject]):
                    self.aNewActsT[subject].append(nKeyT1);
            self.aNewActsT[subject].sort();
    
    def addXmlActs_ToBB(self, sXmlFile=""):
        #Read XML file to get Activities
        self.inputSim.makeXmlActivities(sXmlFile);
        #Insert all XML Activities into the timeline of HMM BB
        self.aNewActsT = dict();
        for i in range(len(self.inputSim.aActivities)): #For all XML Activities
            self.checkOngoingAct(self.inputSim.aActivities[i]);            
            self.addActToBB(self.inputSim.aActivities[i]);
            self.addActCollisions(self.inputSim.aActivities[i]);
        #Add & Link All Activities to the Graph
#         print "aKeys_Time:", self.aKeys_Time;
#         print "aNewActsT:", self.aNewActsT;
        self.getNextActsT();
#         print "aNewActsT:", self.aNewActsT;
        aAddedActs = [];
        for subject in self.aNewActsT.keys():
            for nT in self.aNewActsT[subject]:
                aAddedActs = self.addNodesToGraph(subject, str(nT), aAddedActs);
        self.linkActivities(aAddedActs);
        for subject in self.aNewActsT.keys():
            for nT in self.aNewActsT[subject]:
                self.addMExNodes(subject, str(nT));
#         self.graph.setup();
        
    def addMExNodes(self, subject, sTime):
#         aSubj = []; #Collect all different Subjects in this "t"
#         for actM in self.aActs_Time[subject][sTime]: #For each Activity in this "t"
#             if actM.rootAct.actName=="Null": continue;
#             for sArg in actM.rootAct.aSubjects: #For each Arg (in this Act)
#                 if not(sArg in aSubj) and sArg!="*":
#                     aSubj.append(sArg);
#         if len(aSubj)==0: return;
        if not(self.aMExNodes.has_key((subject,sTime))):
            self.aMExNodes[(subject,sTime)] = [];
            newMExNode = self.createMExNode(sTime, subject); #Create & Update MExNode
#             print "Creating MExNode1:", newMExNode.name;
            self.aMExNodes[(subject,sTime)].append(newMExNode);
        else:
#             for sArg in aSubj: #For each Arg
            bUpdated = False;
            for nodeME in self.aMExNodes[(subject,sTime)]: #For each MExNode
                if subject in nodeME.aSubjects: #If MExNode has this sArg
#                     print "Updating MExNode:", nodeME.name;
                    self.updateMExNode(subject, nodeME); #Update MExNode
                    bUpdated = True;
                    break;
            if not(bUpdated): #If sArg doesn't have a MExNode, then create one
                newMExNode = self.createMExNode(sTime, subject); #Create & Update MExNode
#                 print "Creating MExNode2:", newMExNode.name;
                self.aMExNodes[(subject,sTime)].append(newMExNode);
    
    def removeMExNodes(self, subject, sTime):
#         print "--Checking Time:", sTime;
        if not(self.aMExNodes.has_key((subject,sTime))):
            return;
        aRemMExNodes = [];
        for nodeMEx in self.aMExNodes[(subject,sTime)]: #For each MEx Node in this "t"
#             print "Checking MEx:", nodeMEx.name;
            nParents = 0;
            for parentMEx in self.graph.ndict[nodeMEx][0]: #For each MEx's Parent
                if self.graph.idndict.has_key(parentMEx.sId):
                    nParents += 1;
#             print "MEx_Parents unlinked:", nParents, "from:", len(self.graph.ndict[nodeMEx][0]), "Name:", nodeMEx.name;
            if nParents==0:
                print "Removing MEx:", nodeMEx.name;
                self.graph.removeNode(nodeMEx);
                aRemMExNodes.append(nodeMEx);
            elif nParents>0:
                self.updateMExNode(subject, nodeMEx);
        for remMEx in aRemMExNodes:
            iNodeMEx = self.aMExNodes[(subject,sTime)].index(remMEx);
            del self.aMExNodes[(subject,sTime)][iNodeMEx];        

    def createMExNode(self, sT, sArg):
        sActName = "MEx";
        aSubjects = [sArg];
        sId = "ME_"+sArg+"." + sT;
        aTimes = ["0", sT];
        sSubjects = "(" + ", ".join(aSubjects) + ")";
        sTimes = "[" + "-".join(aTimes) + "]";
        sName = sId+"-"+sActName+"\\n"+sSubjects+"\\n"+sTimes;
        nodeME = self.pgm.Node(sName, sId=sId, actName=sActName, aSubjects=aSubjects, 
                                timeId=int(sT), aTimes=aTimes);
        self.updateMExNode(sArg, nodeME);
        return nodeME;
    
    def updateMExNode(self, subject, nodeME):
        sT = nodeME.aTimes[-1];
        sArg = nodeME.aSubjects[0];
        aNodes, aCondProbs = [], [];  #@UnusedVariable
        aActModels = [];
        for actM in self.aActs_Time[(subject,sT)]:
            if sArg in actM.rootAct.aSubjects: # or actM.rootAct.actName=="Null":
                aNodes.append(actM.rootAct);
                aActModels.append(actM);
#         nNodes = len(aNodes);
#         aCondProbs = [1.0]*nNodes;
#         print "%^Before:", aCondProbs, nNodes, aActModels;
#         aCondProbs = [1.0/float(nNodes)]*nNodes;
        aCondProbs = self.getPlainCPT(aActModels);
#         print "%^After:", aCondProbs2;
        aCPT = self.getCPT(aCondProbs, aNodes, nodeME.aSubjects);
        self.graph.addnode(nodeME, aNodes, aCPT);
    
    def getPlainCPT(self, aActs):
        aCondProbs = [];
        #Find Min P(Obs|~M)
        nMinNullP = float("inf");
        for actM in aActs:
            if actM.nProb_ObsNull<nMinNullP:
                nMinNullP = actM.nProb_ObsNull;
        #Convert (equate) likelihoods P(Obs|M) & P(Obs|~M)
        for actM in aActs:
            if actM.rootAct.actName=="Null":
                actM.rootAct.aScores[0] = nMinNullP;
                aCondProbs.append(nMinNullP);
            else:
                actM.rootAct.aScores[0] = actM.nLikelihood * (nMinNullP/actM.nProb_ObsNull);
                aCondProbs.append(actM.rootAct.aScores[0]);
        return aCondProbs;
            
    def addKeyTime(self, subject, sTime):
        if not(self.aKeys_Time.has_key(subject)):
            self.aKeys_Time[subject] = [sTime];
            return;
        for i in range(1,len(self.aKeys_Time[subject])+1):
            if int(sTime) > int(self.aKeys_Time[subject][-i]):                
                k = len(self.aKeys_Time[subject])-i;
                self.aKeys_Time[subject].insert(k+1, sTime);
                return;
        #Else (if sTime < self.aKeys_Time[0])
        self.aKeys_Time[subject].insert(0, sTime);
    
    def addNodesToGraph(self, subject, sTime, aAddedActs):
        #Add the Nodes
        for aActT1 in self.aActs_Time[(subject,sTime)]: #For each Act[t]
            if not(aActT1 in aAddedActs):
                aAddedActs.append(aActT1);
            if self.graph.ndict.has_key(aActT1.rootAct): continue;
            sAct1 = aActT1.getKeyTexts(); 
            nPrior = self.inputSim.aPriors[self.inputSim.getIndexPrior(sAct1)];
#             print "Adding Node Act:", aActT1.sId, aActT1.rootAct.name, nPrior;
            aActT1.makeXmlGraph(self.graph, nPrior);
#             if not(aAddedActs.has_key(sTime)):
#                 aAddedActs[sTime] = [aActT1];
#             elif not(aActT1 in aAddedActs[sTime]):
#                 aAddedActs[sTime].append(aActT1);
        #Add their Obs Childs
        for aActT1 in self.aActs_Time[(subject,sTime)]: #For each Act[t]
            if len(aActT1.aChildNodes)>0 and self.graph.ndict.has_key(aActT1.aChildNodes[0]): continue;
            aActT1.addChilds(self.graph);
        return aAddedActs;
                
    def getMEx(self, sBinCPT, aActs):
        if sBinCPT.count("1")<2:
            return False;
        #Get All Acts whose CPT entry shows as True
        aActsTrue = [];
        for i, sVal in enumerate(sBinCPT):
#             if sVal=="1" and aActs[i].actName=="Null": #If there are 2 or more True Nodes & one of them is Null, then MEx=True
#                 return True;
            if sVal=="1":
                aActsTrue.append(aActs[i]);
        for actM1 in aActsTrue:
            for actM2 in aActsTrue:
                if actM1!=actM2:
                    for sArg in actM1.aSubjects:
                        if sArg in actM2.aSubjects:
                            return True;
        return False;
    
    def getMissingSubject(self, sBinCPT, aActs, aSubjects):
        for subject in aSubjects:
            bSubjectInPast = False;
            for act in aActs:
                if subject in act.aSubjects:
                    bSubjectInPast = True;
                    break;
            bSubjectFound = False;
            for i, sBin in enumerate(sBinCPT):
                    if sBin=="1" and subject in aActs[i].aSubjects:
                        bSubjectFound = True;
            if bSubjectInPast and not(bSubjectFound):
                return True;
        return False;
            
    def getCPT(self, aCondProbs, aActs, aSubjects):
        aCPT = [];
        nSize = len(aCondProbs);
        for i in range(2**nSize):
            sBinCPT = bin(i)[2:].zfill(nSize); #Get each Binary Number combination
            nProb = 0;
            #Check if there is Mutual Exclusivity Issues or Missing Subjects in this sBinCPT
            if not(self.getMEx(sBinCPT, aActs)) and not(self.getMissingSubject(sBinCPT, aActs, aSubjects)): 
                #Compute Independence Prob (for this entry in CPT)
                nIndActs, nProb = 0, 1;
                aIndActs = [];
                for j, sVal in enumerate(sBinCPT):
                    if sVal=="1":
                        nProb *= aCondProbs[j];
                        nIndActs += 1;
                        aIndActs.append(j);
#                 if len(aIndActs)>1:
#                     for iAct in aIndActs:
#                         print "Independent Act:", aActs[iAct].name;
#                     print "---";
                if nIndActs==0:
                    nProb = 0;
            aCPT.append(nProb);
        return aCPT;
            
    def getPastKey(self, subject, sTime):
        iKey = self.aKeys_Time[subject].index(sTime)-1;
        if iKey<0:
            return None;
        else:
            return self.aKeys_Time[subject][iKey];

    def linkActivities(self, aAddedActs):
        aTo_Nodes, aFrom_Norms = dict(), dict();
        #For each Act[t] (To) Node T1, set their array of parents and cond probs
        for actT1 in aAddedActs:
            aParents, aProbs = [], [];
            for subject in actT1.rootAct.aOnlySubjects:
                aPastActs, sPastTime = [], self.getPastKey(subject, actT1.rootAct.aTimes[-1]);
                aPastActs = self.aActs_Time[(subject, sPastTime)] if sPastTime!=None else [];
                #For each Act[t-1] (From), get each parent node (and its transition to node T1)
                for actT0 in aPastActs:
                    if actT0.rootAct in aParents: continue;
                    nTrans = self.getTrans(actT0, actT1); #Get Transition
                    if nTrans<0: continue; #If the Actor wasn't in past States, then its Trans is zero                    
                    aParents.append(actT0.rootAct); #Accumulate parents into this array
                    aProbs.append(nTrans); #Accumulate Cond Probs into this array
                    #Get Normalizers (for each [From] T0, accumulate all [To] T1 values to normalize P(To|From))
                    if aFrom_Norms.has_key(actT0.rootAct): aFrom_Norms[actT0.rootAct] += nTrans;
                    else: aFrom_Norms[actT0.rootAct] = nTrans;
    #             aParents = [];
    #             for parentAct in aActs:
    #                 aParents.append(parentAct.name);
    #             print "+++", aParents, aProbs;
            aTo_Nodes[actT1] = [aParents, aProbs];
        #For each (To) Node T1
        for actT1 in aTo_Nodes: 
            for i,actT0 in enumerate(aTo_Nodes[actT1][0]): #For each Parent T0 [From]
                aTo_Nodes[actT1][1][i] /= aFrom_Norms[actT0]; #Normalize it
            if len(aTo_Nodes[actT1][0])>0: #If there are past states (parent nodes), then get correct CPT
                aProbs = self.getCPT(aTo_Nodes[actT1][1], aTo_Nodes[actT1][0], actT1.aSubjects);
#                 aParents = [];
#                 for parentAct in aTo_Nodes[actT1][0]:
#                     aParents.append(parentAct.name);
#                 print "Noisy-OR (CPT from "+ actT1.rootAct.name +"):", aProbs, aTo_Nodes[actT1][1], aParents;
            else: #If is 1st Time-Step or wasn't past state with same Actor, then is Prior
                aProbs = [self.getPrior(actT1)];
            aActs = aTo_Nodes[actT1][0];
#             aParents = [];
#             for parentAct in aActs:
#                 aParents.append(parentAct.name);
#             print "+++2", aParents, aProbs;
            self.graph.addnode(actT1.rootAct, aActs, aProbs);
         
    def getPrior(self, activity):
        sAct = activity.getKeyTexts();
        iPrior = self.inputSim.getIndexPrior(sAct);
        nPrior = self.inputSim.aPriors[iPrior];
        return nPrior;
     
    def getTrans(self, act0, act1):
        sAct0 = act0.getKeyTexts();
        sAct1 = act1.getKeyTexts();
        [nIndexA0, nIndexA1] = self.inputSim.getIndex(sAct0, sAct1);  # @UnusedVariable
        if nIndexA0==-1: 
            return -1;
        sCodeT0, sCodeT1 = act0.sId.split(".")[0], act1.sId.split(".")[0];
        initTimeT1, nRealInitT1 = int(act1.rootAct.aTimes[0]), act1.rootAct.nRealInitT;
        #If Transition T0->T1 is to Itself or T1 is starting or T1 is Null, then bCanMakeLink==True
        bCanMakeLink = sCodeT0==sCodeT1 or initTimeT1==nRealInitT1 or act1.rootAct.actName=="Null";
        if nIndexA0!=None and bCanMakeLink:
            return self.inputSim.aTrans[nIndexA0][nIndexA1];
        else:
            return -1;
            
    def printGraph(self, bPrior=True):
        aAllNodes = self.graph.ndict.keys();
#         if bPrior==True:
#             aPriors = self.graph.priorprob(aAllNodes);
#             print aPriors;
#         else:
#             aPosts = self.graph.postprob(aAllNodes);
        for i in range(len(aAllNodes)):
            print "Node " + str(i+1) + ": " + aAllNodes[i].name;
#             if bPrior==True:
#                 print "Prior: " + str(aPriors[i]);
#             else:
#                 print "Posterior: " + str(aPosts[i]);                
            for j in range(len(self.graph.ndict[aAllNodes[i]][0])):
                print "Parent " + str(j+1) + ": " + self.graph.ndict[aAllNodes[i]][0][j].name;
            sCPT_F = "[" + "%.4f" % (1.0-float(self.graph.ndict[aAllNodes[i]][1][0]));
            for j in range(1, len(self.graph.ndict[aAllNodes[i]][1])):
                sCPT_F += ", %.4f" % (1.0-float(self.graph.ndict[aAllNodes[i]][1][j]));
            sCPT_F += "]";
            sCPT_T = "[" + "%.4f" % self.graph.ndict[aAllNodes[i]][1][0];
            for j in range(1, len(self.graph.ndict[aAllNodes[i]][1])):
                sCPT_T += ", %.4f" % self.graph.ndict[aAllNodes[i]][1][j];
            sCPT_T += "]";
            print "CPT-False: " + sCPT_F;
            print "CPT-True:  " + sCPT_T;
            print "";
                
